package com.bj58.ecdata.calc.dbservice.service.impl;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import redis.clients.jedis.Tuple;

import com.bj58.ecdata.calc.dbservice.consts.Constant;
import com.bj58.ecdata.calc.dbservice.dao.ClickDao;
import com.bj58.ecdata.calc.dbservice.dao.model.ClickModel;
import com.bj58.ecdata.calc.dbservice.dao.model.ClickResultData;
import com.bj58.ecdata.calc.dbservice.dao.model.DataPoint;
import com.bj58.ecdata.calc.dbservice.handler.CPCClickDetails;
import com.bj58.ecdata.calc.dbservice.load.SpringUtils;
import com.bj58.ecdata.calc.dbservice.model.ResultObj;
import com.bj58.ecdata.calc.dbservice.service.BusslineEnum;
import com.bj58.ecdata.calc.dbservice.service.ClickService;
import com.bj58.ecdata.calc.dbservice.service.MapTopTypeEnum;
import com.bj58.ecdata.calc.dbservice.service.MarketTypeEnum;
import com.bj58.ecdata.calc.dbservice.service.PlatformEnum;
import com.bj58.ecdata.exception.BusinessException;
import com.bj58.ecdata.util.ArithUtil;
import com.bj58.ecdata.util.DateUtils;
import com.bj58.ecdata.util.JsonUtils;
import com.bj58.ecdata.util.NumberUtils;
import com.bj58.spat.scf.server.contract.annotation.ServiceBehavior;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * @author lichao
 *
 */
@ServiceBehavior
public class ClickServiceImpl extends BaseServiceImpl implements ClickService {
	Logger log = LoggerFactory.getLogger(ClickServiceImpl.class);

	private ClickDao dao = SpringUtils.getInstance().getBean(ClickDao.class);

	public ClickServiceImpl() {
		super(Lists.newArrayList("pv", "cash", "cost", "custNum"));
	}

	@Override
	public String getDailySum() {
		long pv = dao.loadDailySum("pv");
		ClickModel model = new ClickModel();
		model.setTime(DateUtils.getTruncatedToday());
		long cash = dao.loadDailySum("cash", model);
		ClickResultData data = new ClickResultData();
		data.setTime(dao.getLatest());
		data.setPv(pv);
		data.setCash(cash / 100);
		return JsonUtils.toJson(data);
	}

	@Override
	public String getDailySum(PlatformEnum platform, BusslineEnum bussline) {
		ClickModel model = new ClickModel();
		model.setTime(DateUtils.getTruncatedToday());
		model.setPlatform(platform != null ? platform.value() : null);
		model.setBussline(bussline != null ? bussline.value() : null);

		long cash = dao.loadDailySum("cash", model);
		long cost = dao.loadDailySum("cost", model);

		ClickResultData data = new ClickResultData();
		data.setCash(cash / 100);
		data.setCost(cost / 100);
		data.setTime(dao.getLatest());
		return JsonUtils.toJson(data);
	}

	@Override
	public String getData(String type, PlatformEnum platform, BusslineEnum bussline, long time) {

		checkType(type);

		long endTime = dao.getLatest();
		List<ClickModel> params = createModels(time, endTime, Constant._2s, Constant._1h, platform, bussline);
		List<DataPoint> datas = dao.load(type, params, isDiv(type));
		Map<String, Object> result = Maps.newHashMap();
		result.put("data", datas);
		return JsonUtils.toJson(result);
	}

	@Override
	public String getDataTodayHourly(String type, PlatformEnum platform, BusslineEnum bussline) {

		checkType(type);

		long zeroTime = DateUtils.getTruncatedToday();
		long curTime = dao.getLatest();
		long endTime = DateUtils.truncateToHour(curTime) - Constant._1h;
		List<ClickModel> params = createModels(0, endTime, Constant._1h, endTime - zeroTime + Constant._1h, platform, bussline);
		List<DataPoint> datas = dao.loadHourly(type, params, isDiv(type));
		Map<String, Object> result = Maps.newHashMap();
		result.put("data", datas);
		return JsonUtils.toJson(result);
	}

	@Override
	public String getDataYesterdayHourly(String type, PlatformEnum platform, BusslineEnum bussline) {

		checkType(type);

		long endTime = DateUtils.getTruncatedToday() - Constant._1h;
		List<ClickModel> params = createModels(0, endTime, Constant._1h, Constant._1d, platform, bussline);
		List<DataPoint> datas = dao.loadHourly(type, params, isDiv(type));
		Map<String, Object> result = Maps.newHashMap();
		result.put("data", datas);
		return JsonUtils.toJson(result);
	}

	private List<ClickModel> createModels(long startTime, long endTime, long interval, long span, PlatformEnum platform, BusslineEnum bussline) {
		long minTime = endTime - span;
		if (startTime == 0 || startTime < minTime) {
			startTime = minTime;
		}

		List<ClickModel> models = Lists.newArrayList();
		for (long i = startTime + interval; i <= endTime; i += interval) {

			ClickModel model = new ClickModel();
			model.setTime(i);
			model.setPlatform(platform != null ? platform.value() : null);
			model.setBussline(bussline != null ? bussline.value() : null);
			models.add(model);
		}
		return models;
	}

	@Override
	public String getMapDataWithCity(MarketTypeEnum marketType, int pointNum) {
		if (marketType == null) {
			throw new BusinessException("error marketType");
		}

		if (pointNum < 1) {
			pointNum = 1;
		}

		if (pointNum > 30) {
			pointNum = 30;
		}

		long endTime = dao.getLatest();
		List<ClickModel> models = createClickMapModels(pointNum, endTime, Constant._2s, marketType);
		Map<String, Long> map = dao.loadUnionMapByCityType(models);

		List<ClickResultData> list = Lists.newArrayList();
		for (Entry<String, Long> entry : map.entrySet()) {
			ClickResultData item = new ClickResultData();
			item.setCity(entry.getKey());
			item.setValue(entry.getValue());
			list.add(item);
		}

		DataPoint data = new DataPoint(endTime, list);

		ResultObj result = new ResultObj();
		result.setData(Lists.newArrayList(data));

		return JsonUtils.toJson(result);
	}

	private List<ClickModel> createClickMapModels(int num, long endTime, long interval, MarketTypeEnum marketType) {

		long startTime = endTime - (interval * num);

		List<ClickModel> models = Lists.newArrayList();
		for (long i = startTime + interval; i <= endTime; i += interval) {

			ClickModel model = new ClickModel();
			model.setTime(i);
			model.setCityType(marketType.value());
			models.add(model);
		}
		return models;
	}

	@Override
	public String getMapDataDetail(int count, long time) {
		long minTime = time + 1;
		long maxTime = dao.getLatest();
		if (maxTime <= minTime) {
			maxTime = Long.MAX_VALUE;
			log.error("request time({}) < latestTime({})", time, maxTime);
		}
		Set<Tuple> tuples = dao.loadsDetail(count, minTime, maxTime);
		List<ClickResultData> datas = Lists.newArrayList();
		for (Tuple tuple : tuples) {
			CPCClickDetails detail = JsonUtils.fromJSON(tuple.getElement(), CPCClickDetails.class);
			ClickResultData item = new ClickResultData();
			item.setTime(detail.getClickTime());
			item.setUserId(detail.getCustomerId());
			item.setCity(detail.getCity1Name());
			item.setCate(detail.getCate2Name());
			item.setPlatform(convertToPlatformName(NumberUtils.toInt(detail.getPlatform())));
			item.setCash(ArithUtil.div(detail.getCash(), 100));
			item.setCost(ArithUtil.div(detail.getCost(), 100));
			datas.add(item);
		}

		ResultObj result = new ResultObj();
		result.setData(datas);
		return JsonUtils.toJson(result);
	}

	private String convertToPlatformName(int value) {
		switch (value) {
		case -1:
			return PlatformEnum.PC.name();
		case 0:
			return PlatformEnum.M.name();
		case 1:
			return PlatformEnum.WAP.name();
		case 2:
			return PlatformEnum.APP.name();
		default:
			return "null";
		}

	}

	@Override
	public String getMapTopList(MapTopTypeEnum type, int count) {

		if (type == null) {
			throw new BusinessException("error type");
		}
		if (count < 1) {
			count = 1;
		}

		Set<Tuple> list = dao.loadsTopList(type.value(), count);
		List<ClickResultData> data = Lists.newArrayList();
		for (Tuple tuple : list) {
			ClickResultData item = new ClickResultData();
			item.setCash(ArithUtil.div(tuple.getScore(), 100));

			switch (type) {
			case CITY:
				item.setCity(tuple.getElement());
				break;
			case CATE:
				item.setCate(tuple.getElement());
				break;
			}

			data.add(item);
		}

		ResultObj result = new ResultObj();
		result.setData(data);
		return JsonUtils.toJson(result);
	}

}
